- Main Page
- Related Pages
- Files

# uart.c

Go to the documentation of this file.

    00001 /*
    00002  * $Id: uart.c,v 1.4 2008/03/16 21:14:08 joerg_wunsch Exp $
    00003  *
    00004  ****************************************************************************
    00005  *
    00006  * simulavr - A simulator for the Atmel AVR family of microcontrollers.
    00007  * Copyright (C) 2003, 2004  Keith Gudger
    00008  *
    00009  * This program is free software; you can redistribute it and/or modify
    00010  * it under the terms of the GNU General Public License as published by
    00011  * the Free Software Foundation; either version 2 of the License, or
    00012  * (at your option) any later version.
    00013  *
    00014  * This program is distributed in the hope that it will be useful,
    00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00017  * GNU General Public License for more details.
    00018  *
    00019  * You should have received a copy of the GNU General Public License
    00020  * along with this program; if not, write to the Free Software
    00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    00022  *
    00023  ****************************************************************************
    00024  */
    00025
    00026 /**
    00027  * \file uart.c
    00028  * \brief Module to simulate the AVR's uart module.
    00029  */
    00030
    00031 #include <config.h>
    00032
    00033 #include <stdio.h>
    00034 #include <stdlib.h>
    00035 #include <string.h>
    00036
    00037 #include "avrerror.h"
    00038 #include "avrmalloc.h"
    00039 #include "avrclass.h"
    00040 #include "utils.h"
    00041 #include "callback.h"
    00042 #include "op_names.h"
    00043
    00044 #include "storage.h"
    00045 #include "flash.h"
    00046
    00047 #include "vdevs.h"
    00048 #include "memory.h"
    00049 #include "stack.h"
    00050 #include "register.h"
    00051 #include "sram.h"
    00052 #include "eeprom.h"
    00053 #include "timers.h"
    00054 #include "ports.h"
    00055 #include "uart.h"
    00056
    00057 #include "avrcore.h"
    00058
    00059 #include "intvects.h"
    00060
    00061 /****************************************************************************\
    00062  *
    00063  * uart Interrupts
    00064  *
    00065 \****************************************************************************/
    00066
    00067 static void uart_iadd_addr (VDevice *vdev, int addr, char *name, int rel_addr,
    00068                             void *data);
    00069 static uint8_t uart_intr_read (VDevice *dev, int addr);
    00070 static void uart_intr_write (VDevice *dev, int addr, uint8_t val);
    00071 static void uart_intr_reset (VDevice *dev);
    00072 static int uart_intr_cb (uint64_t time, AvrClass *data);
    00073
    00074 unsigned int UART_Int_Table[] = {
    00075     irq_vect_table_index (UART_RX), /* uart Rx complete */
    00076     irq_vect_table_index (UART_UDRE), /* uart data register empty */
    00077     irq_vect_table_index (UART_TX) /* uart Tx complete */
    00078 };
    00079
    00080 unsigned int UART0_Int_Table[] = {
    00081     irq_vect_table_index (USART0_RX), /* uart Rx complete */
    00082     irq_vect_table_index (USART0_UDRE), /* uart data register empty */
    00083     irq_vect_table_index (USART0_TX) /* uart Tx complete */
    00084 };
    00085
    00086 unsigned int UART1_Int_Table[] = {
    00087     irq_vect_table_index (USART1_RX), /* uart Rx complete */
    00088     irq_vect_table_index (USART1_UDRE), /* uart data register empty */
    00089     irq_vect_table_index (USART1_TX) /* uart Tx complete */
    00090 };
    00091
    00092 /** \brief Allocate a new uart interrupt */
    00093
    00094 VDevice *
    00095 uart_int_create (int addr, char *name, int rel_addr, void *data)
    00096 {
    00097     if (data)
    00098         return (VDevice *)uart_intr_new (addr, name, data);
    00099     else
    00100         avr_error ("Attempted UART create with NULL data pointer");
    00101     return 0;
    00102 }
    00103
    00104 UARTIntr_T *
    00105 uart_intr_new (int addr, char *name, void *data)
    00106 {
    00107     uint8_t *uart_num = (uint8_t *) data;
    00108     UARTIntr_T *uart;
    00109
    00110     uart = avr_new (UARTIntr_T, 1);
    00111     uart_intr_construct (uart, addr, name);
    00112     class_overload_destroy ((AvrClass *)uart, uart_intr_destroy);
    00113
    00114     if (*uart_num == USART0)
    00115         uart->Int_Table = &UART0_Int_Table[0];
    00116     else if (*uart_num == USART1)
    00117         uart->Int_Table = &UART1_Int_Table[0];
    00118     else
    00119         uart->Int_Table = &UART_Int_Table[0];
    00120
    00121     uart_iadd_addr ((VDevice *)uart, addr, name, 0, NULL);
    00122     return uart;
    00123 }
    00124
    00125 /** \brief Constructor for uart interrupt object. */
    00126
    00127 void
    00128 uart_intr_construct (UARTIntr_T *uart, int addr, char *name)
    00129 {
    00130     if (uart == NULL)
    00131         avr_error ("passed null ptr");
    00132
    00133     vdev_construct ((VDevice *)uart, uart_intr_read, uart_intr_write,
    00134                     uart_intr_reset, uart_iadd_addr);
    00135
    00136     uart_intr_reset ((VDevice *)uart);
    00137 }
    00138
    00139 static void
    00140 uart_iadd_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
    00141 {
    00142     UARTIntr_T *uart = (UARTIntr_T *)vdev;
    00143
    00144     if (strncmp ("UBRRH", name, 5) == 0)
    00145     {
    00146         uart->ubrrh_addr = addr;
    00147     }
    00148
    00149     else if ((strncmp ("UBRR", name, 4) == 0)
    00150              || (strncmp ("UBRR0", name, 5) == 0)
    00151              || (strncmp ("UBRR1", name, 5) == 0))
    00152     {
    00153         uart->ubrrl_addr = addr;
    00154     }
    00155
    00156     else if ((strncmp ("USR", name, 3) == 0)
    00157              || (strncmp ("UCSR0A", name, 6) == 0)
    00158              || (strncmp ("UCSR1A", name, 6) == 0))
    00159     {
    00160         uart->usr_addr = addr;
    00161     }
    00162
    00163     else if ((strncmp ("UCR", name, 3) == 0)
    00164              || (strncmp ("UCSR0B", name, 6) == 0)
    00165              || (strncmp ("UCSR1B", name, 6) == 0))
    00166     {
    00167         uart->ucr_addr = addr;
    00168     }
    00169
    00170     else
    00171     {
    00172         avr_error ("invalid UART register name: '%s' @ 0x%04x", name, addr);
    00173     }
    00174 }
    00175
    00176 /** \brief Destructor for uart interrupt object. */
    00177
    00178 void
    00179 uart_intr_destroy (void *uart)
    00180 {
    00181     if (uart == NULL)
    00182         return;
    00183
    00184     vdev_destroy (uart);
    00185 }
    00186
    00187 static uint8_t
    00188 uart_intr_read (VDevice *dev, int addr)
    00189 {
    00190     UARTIntr_T *uart = (UARTIntr_T *)dev;
    00191
    00192     if (addr == uart->ubrrl_addr)
    00193     {
    00194         return (uart->ubrr & 0xff);
    00195     }
    00196
    00197     else if (addr == uart->ubrrh_addr)
    00198     {
    00199         return (uart->ubrr >> 8);
    00200     }
    00201
    00202     else if (addr == uart->ucr_addr)
    00203     {
    00204         return (uart->ucr);
    00205     }
    00206
    00207     else if (addr == uart->usr_addr)
    00208     {
    00209         return (uart->usr);
    00210     }
    00211
    00212     else
    00213     {
    00214         avr_error ("Bad address: 0x%04x", addr);
    00215     }
    00216
    00217     return 0;                   /* will never get here */
    00218 }
    00219
    00220 static void
    00221 uart_intr_write (VDevice *dev, int addr, uint8_t val)
    00222 {
    00223     UARTIntr_T *uart = (UARTIntr_T *)dev;
    00224     CallBack *cb;
    00225
    00226     if (addr == uart->ubrrl_addr)
    00227     {
    00228         uart->ubrr = val + (uart->ubrr_temp << 8);
    00229     }
    00230
    00231     else if (addr == uart->ubrrh_addr)
    00232     {
    00233         uart->ubrr_temp = val;
    00234     }
    00235
    00236     else if (addr == uart->usr)
    00237     {
    00238         if (val & mask_TXC)
    00239             uart->usr &= ~mask_TXC;
    00240     }
    00241
    00242     else if (addr == uart->ucr_addr)
    00243     {
    00244         (uart->ucr = val);      /* look for interrupt enables */
    00245
    00246         if (((uart->ucr & mask_TXEN) && (uart->ucr & mask_TXCIE))
    00247             || ((uart->ucr & mask_RXEN) && (uart->ucr & mask_RXCIE))
    00248             || (uart->ucr & mask_UDRIE))
    00249         {
    00250             if (uart->intr_cb == NULL)
    00251             {
    00252                 /* we need to install the intr_cb function */
    00253                 cb = callback_new (uart_intr_cb, (AvrClass *)uart);
    00254                 uart->intr_cb = cb;
    00255                 avr_core_async_cb_add ((AvrCore *)vdev_get_core (dev), cb);
    00256             }
    00257         }
    00258         else
    00259         {
    00260             uart->intr_cb = NULL;
    00261             /* no interrupt are enabled, remove the callback */
    00262         }
    00263     }
    00264
    00265     else
    00266     {
    00267         avr_error ("Bad address: 0x%04x", addr);
    00268     }
    00269 }
    00270
    00271 static void
    00272 uart_intr_reset (VDevice *dev)
    00273 {
    00274     UARTIntr_T *uart = (UARTIntr_T *)dev;
    00275
    00276     uart->intr_cb = NULL;
    00277
    00278     uart->ubrr = 0;
    00279     uart->usr = 0;
    00280     uart->ucr = 0;
    00281     uart->usr_shadow = 0;
    00282 }
    00283
    00284 static int
    00285 uart_intr_cb (uint64_t time, AvrClass *data)
    00286 {
    00287     UARTIntr_T *uart = (UARTIntr_T *)data;
    00288
    00289     if (uart->intr_cb == NULL)
    00290         return CB_RET_REMOVE;
    00291
    00292     if ((uart->ucr & mask_RXCIE) && (uart->usr & mask_RXC))
    00293         /* an enabled interrupt occured */
    00294     {
    00295         AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)uart);
    00296         avr_core_irq_raise (core, (uart->Int_Table[URX]));
    00297     }
    00298
    00299     if ((uart->ucr & mask_TXCIE) && (uart->usr & mask_TXC))
    00300         /* an enabled interrupt occured */
    00301     {
    00302         AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)uart);
    00303         avr_core_irq_raise (core, (uart->Int_Table[UTX]));
    00304         uart->usr &= ~mask_TXC;
    00305     }
    00306
    00307     if ((uart->ucr & mask_UDRIE) && (uart->usr & mask_UDRE)
    00308         && (uart->usr_shadow & mask_UDRE))
    00309         /* an enabled interrupt occured */
    00310     {
    00311         AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)uart);
    00312         avr_core_irq_raise (core, (uart->Int_Table[UUDRE]));
    00313         uart->usr_shadow &= ~mask_UDRE; /* only issue one interrupt / udre */
    00314     }
    00315
    00316     return CB_RET_RETAIN;
    00317 }
    00318
    00319 /****************************************************************************\
    00320  *
    00321  * uart
    00322  *
    00323 \****************************************************************************/
    00324
    00325 static void uart_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
    00326                            void *data);
    00327 static uint8_t uart_read (VDevice *dev, int addr);
    00328 static void uart_write (VDevice *dev, int addr, uint8_t val);
    00329 static void uart_reset (VDevice *dev);
    00330 static int uart_clk_incr_cb (uint64_t ck, AvrClass *data);
    00331
    00332 /** \brief Allocate a new uart structure. */
    00333
    00334 VDevice *
    00335 uart_create (int addr, char *name, int rel_addr, void *data)
    00336 {
    00337     return (VDevice *)uart_new (addr, name, rel_addr);
    00338 }
    00339
    00340 UART_T *
    00341 uart_new (int addr, char *name, int rel_addr)
    00342 {
    00343     UART_T *uart;
    00344
    00345     uart = avr_new (UART_T, 1);
    00346     uart_construct (uart, addr, name, rel_addr);
    00347
    00348     class_overload_destroy ((AvrClass *)uart, uart_destroy);
    00349
    00350     return uart;
    00351 }
    00352
    00353 /** \brief Constructor for uart object. */
    00354
    00355 void
    00356 uart_construct (UART_T *uart, int addr, char *name, int rel_addr)
    00357 {
    00358     if (uart == NULL)
    00359         avr_error ("passed null ptr");
    00360
    00361     vdev_construct ((VDevice *)uart, uart_read, uart_write, uart_reset,
    00362                     uart_add_addr);
    00363
    00364     uart_add_addr ((VDevice *)uart, addr, name, 0, NULL);
    00365     if (rel_addr)
    00366         uart->related_addr = rel_addr;
    00367     uart_reset ((VDevice *)uart);
    00368 }
    00369
    00370 static void
    00371 uart_add_addr (VDevice *vdev, int addr, char *name, int ref_addr, void *data)
    00372 {
    00373     UART_T *uart = (UART_T *)vdev;
    00374
    00375     if (strncmp ("UDR", name, 3) == 0)
    00376     {
    00377         uart->udr_addr = addr;
    00378     }
    00379
    00380     else
    00381     {
    00382         avr_error ("invalid SPI register name: '%s' @ 0x%04x", name, addr);
    00383     }
    00384 }
    00385
    00386 /** \brief Destructor for uart object. */
    00387
    00388 void
    00389 uart_destroy (void *uart)
    00390 {
    00391     if (uart == NULL)
    00392         return;
    00393
    00394     vdev_destroy (uart);
    00395 }
    00396
    00397 static uint8_t
    00398 uart_read (VDevice *dev, int addr)
    00399 {
    00400     UART_T *uart = (UART_T *)dev;
    00401     UARTIntr_T *uart_t;
    00402     uint16_t udr_temp;
    00403
    00404     uart_t =
    00405         (UARTIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
    00406                                                  vdev_get_core ((VDevice *)
    00407                                                                 uart),
    00408                                                  uart->related_addr);
    00409
    00410     if (addr == uart->udr_addr)
    00411     {
    00412         uart_t->usr &= ~mask_RXC; /* clear RXC bit in USR */
    00413         if (uart->clk_cb)       /* call back already installed */
    00414         {
    00415             udr_temp = uart_port_rd (addr);
    00416             uart->udr_rx = (uint8_t) udr_temp; /* lower 8 bits */
    00417             if ((uart_t->ucr & mask_CHR9) && /* 9 bits rec'd */
    00418                 (udr_temp & (1 << 8))) /* hi bit set */
    00419                 uart_t->ucr |= mask_RXB8;
    00420             else
    00421                 uart_t->ucr &= ~mask_RXB8;
    00422         }
    00423         return uart->udr_rx;
    00424     }
    00425
    00426     else
    00427     {
    00428         avr_error ("Bad address: 0x%04x", addr);
    00429     }
    00430
    00431     return 0;                   /* will never get here */
    00432 }
    00433
    00434 static void
    00435 uart_write (VDevice *dev, int addr, uint8_t val)
    00436 {
    00437     UART_T *uart = (UART_T *)dev;
    00438     UARTIntr_T *uart_t;
    00439     CallBack *cb;
    00440
    00441     uart_t =
    00442         (UARTIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
    00443                                                  vdev_get_core ((VDevice *)
    00444                                                                 uart),
    00445                                                  uart->related_addr);
    00446
    00447     if (addr == uart->udr_addr)
    00448     {
    00449         if (uart_t->usr & mask_UDRE)
    00450         {
    00451             uart_t->usr &= ~mask_UDRE;
    00452             uart_t->usr_shadow &= ~mask_UDRE;
    00453         }
    00454         else
    00455         {
    00456             uart_t->usr |= mask_UDRE;
    00457             uart_t->usr_shadow |= mask_UDRE;
    00458         }
    00459         uart->udr_tx = val;
    00460
    00461         /*
    00462          * When the user writes to UDR, a callback is installed for
    00463          * clock generated increments.
    00464          */
    00465
    00466         uart->divisor = (uart_t->ubrr + 1) * 16;
    00467
    00468         /* install the clock incrementor callback (with flair!) */
    00469
    00470         if (uart->clk_cb == NULL)
    00471         {
    00472             cb = callback_new (uart_clk_incr_cb, (AvrClass *)uart);
    00473             uart->clk_cb = cb;
    00474             avr_core_clk_cb_add ((AvrCore *)vdev_get_core ((VDevice *)uart),
    00475                                  cb);
    00476         }
    00477
    00478         /* set up timer for 8 or 9 clocks based on ucr
    00479            (includes start and stop bits) */
    00480
    00481         uart->tcnt = (uart_t->ucr & mask_CHR9) ? 11 : 10;
    00482     }
    00483
    00484     else
    00485     {
    00486         avr_error ("Bad address: 0x%04x", addr);
    00487     }
    00488 }
    00489
    00490 static void
    00491 uart_reset (VDevice *dev)
    00492 {
    00493     UART_T *uart = (UART_T *)dev;
    00494
    00495     uart->clk_cb = NULL;
    00496
    00497     uart->udr_rx = 0;
    00498     uart->udr_tx = 0;
    00499     uart->tcnt = 0;
    00500     uart->divisor = 0;
    00501 }
    00502
    00503 static int
    00504 uart_clk_incr_cb (uint64_t ck, AvrClass *data)
    00505 {
    00506     UART_T *uart = (UART_T *)data;
    00507     UARTIntr_T *uart_t;
    00508     uint8_t last = uart->tcnt;
    00509
    00510     uart_t =
    00511         (UARTIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
    00512                                                  vdev_get_core ((VDevice *)
    00513                                                                 uart),
    00514                                                  uart->related_addr);
    00515
    00516     if (uart->clk_cb == NULL)
    00517         return CB_RET_REMOVE;
    00518
    00519     if (uart->divisor <= 0)
    00520         avr_error ("Bad divisor value: %d", uart->divisor);
    00521
    00522     /* decrement clock if ck is a mutliple of divisor */
    00523
    00524     uart->tcnt -= ((ck % uart->divisor) == 0);
    00525
    00526     if (uart->tcnt != last)     /* we've changed the counter */
    00527     {
    00528         if (uart->tcnt == 0)
    00529         {
    00530             if (uart_t->usr & mask_UDRE) /* data register empty */
    00531             {
    00532                 uart_t->usr |= mask_TXC;
    00533                 uart->clk_cb = NULL;
    00534                 return CB_RET_REMOVE;
    00535             }
    00536             else                /* there's a byte waiting to go */
    00537             {
    00538                 uart_t->usr |= mask_UDRE;
    00539                 uart_t->usr_shadow |= mask_UDRE; /* also write shadow */
    00540
    00541                 /* set up timer for 8 or 9 clocks based on ucr,
    00542                    (includes start and stop bits) */
    00543
    00544                 uart->tcnt = (uart_t->ucr & mask_CHR9) ? 11 : 10;
    00545             }
    00546         }
    00547     }
    00548
    00549     return CB_RET_RETAIN;
    00550 }
    00551
    00552 uint16_t
    00553 uart_port_rd (int addr)
    00554 {
    00555     int data;
    00556     char line[80];
    00557
    00558     while (1)
    00559     {
    00560         fprintf (stderr,
    00561                  "\nEnter 9 bits of hex data to read into the uart at "
    00562                  "address 0x%04x: ", addr);
    00563
    00564         /* try to read in a line of input */
    00565         if (fgets (line, sizeof (line), stdin) == NULL)
    00566             continue;
    00567
    00568         /* try to parse the line for a byte of data */
    00569         if (sscanf (line, "%x\n", &data) != 1)
    00570             continue;
    00571
    00572         break;
    00573     }
    00574
    00575     return (uint16_t) (data & 0x1ff);
    00576 }
    00577
    00578 void
    00579 uart_port_wr (uint8_t val)
    00580 {
    00581     fprintf (stderr, "wrote 0x%02x to uart\n", val);
    00582 }

Automatically generated by Doxygen 1.5.5 on 7 Nov 2008.